/*
 * Project: GraphicLCD Arduino Library
 *
 * Source Name: GraphicLCD.cpp
 * Created on: 18/AUG/2009
 *
 * Copyright (c) 2009 Tiago Barros.
 * All rights reserved.
 *
 * Code contributions from: 
 *   - Markos Kyritsis (PhillipsLCD lib)
 *   - James Lynch (Nokia 6100 LCD Display Driver)
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, 
 *   this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice, 
 *   this list of conditions and the following disclaimer in the documentation 
 *   and/or other materials provided with the distribution.
 * - Neither the name of tiagobarros.org nor the names of its contributors may be 
 *   used to endorse or promote products derived from this software without 
 *   specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * REVISION HISTORY:
 *
 * Date         Author(s)
 * Version      Headline
 * ===========  ==============================================================
 * 18/AUG/2009  Tiago Barros
 * 00.10        Initial Creation
 * ===========  ==============================================================
 *
 *
 *
 * ---------------------------------------------------------------------------
 *  General Description: This file implements the GraphicLCD class. 
 *  This class provides the graphic primitives for use the 128x128 Graphic LCD
 *  with Philips PCF8833 Controller. This LCD is found on some Nokia phones 
 *  like 6560, 3105, 3120, 3200, 3205, 5140, 6030, 6225, 6585, 7210, 7250 
 *  and 7250i. Sparkfun also sels this LCD on the following link:
 *  http://www.sparkfun.com/commerce/product_info.php?products_id=569
 *
 *  LCD with Phillips controller has a brown pcb. LCD with Epson controller
 *  has a green PCB.
 *  This library does not work with Epson S1D15G10 controller yet.
 * ---------------------------------------------------------------------------
 */

// include core Wiring API
#include "WProgram.h"

// include this library's description file
#include "GraphicLCD.h"

#ifdef TIAGOBARROS_ORG_LCD_SHIELD
// LCD pin operations (optimized for performance - not using digitalWrite() etc)
#define cbi(reg, bit) (reg&=~(1<<bit))
#define sbi(reg, bit) (reg|= (1<<bit))

#define LCD_CS0 cbi(PORTD,LCD_CS)
#define LCD_CS1 sbi(PORTD,LCD_CS)

#define LCD_SCLK0 cbi(PORTD,LCD_SCLK)
#define LCD_SCLK1 sbi(PORTD,LCD_SCLK)

#define LCD_RESET0 cbi(PORTD,LCD_RESET)
#define LCD_RESET1 sbi(PORTD,LCD_RESET)

#define LCD_SDATA0 (PORTB &= 0xFE)
#define LCD_SDATA1 (PORTB |= 0x01)
#define LCD_SET_SDATA(bit) PORTB |= (bit & 0x01); PORTB &= (bit | 0xFE);  

#else
// LCD pin operations using digitalWrite() - not optimized
#define LCD_CS0 digitalWrite(LCD_CS, LOW)
#define LCD_CS1 digitalWrite(LCD_CS, HIGH)

#define LCD_SCLK0 digitalWrite(LCD_SCLK, LOW)
#define LCD_SCLK1 digitalWrite(LCD_SCLK, HIGH)

#define LCD_RESET0 digitalWrite(LCD_RESET, LOW)
#define LCD_RESET1 digitalWrite(LCD_RESET, HIGH)

#define LCD_SDATA0 digitalWrite(LCD_SDATA, LOW)
#define LCD_SDATA1 digitalWrite(LCD_SDATA, HIGH)
#define LCD_SET_SDATA(bit) digitalWrite(LCD_SDATA, (bit & 0x01));
#endif

//********************************************************************
//
//			PHILLIPS Controller Definitions
//
//********************************************************************
//LCD Commands
#define	NOPP        0x00
#define	SWRESET     0x01
#define	BSTRON      0x03
#define SLEEPIN     0x10
#define	SLEEPOUT    0x11
#define	NORON       0x13
#define	INVOFF      0x20
#define INVON       0x21
#define	SETCON      0x25
#define DISPOFF     0x28
#define DISPON      0x29
#define CASETP      0x2A
#define PASETP      0x2B
#define RAMWRP      0x2C
#define RGBSET      0x2D
#define	MADCTL      0x36
#define	COLMOD      0x3A
#define DISCTR      0xB9
#define	EC          0xC0

// Constructor /////////////////////////////////////////////////////////////////
// Function that handles the creation and setup of instances

GraphicLCD::GraphicLCD()
{

}

// Public Methods //////////////////////////////////////////////////////////////
// Functions available in Wiring sketches, this library, and other libraries

void GraphicLCD::Init()	// Initialise the screen
{
    pinMode(LCD_RESET, OUTPUT);
    pinMode(LCD_CS, OUTPUT);
    pinMode(LCD_SCLK, OUTPUT);
    pinMode(LCD_SDATA, OUTPUT);

    // LCD Hardware reset
    LCD_CS0;
    LCD_SDATA0;
    LCD_SCLK1;
    LCD_RESET1;

    delay(20);
    LCD_RESET0;
    delay(20);
    LCD_RESET1;
    delay(20);

    WriteCommand(SWRESET);       // software reset

    WriteCommand(SLEEPOUT);      // SleepOut
    WriteCommand(BSTRON);        // Booster On
    delay(10);
    WriteCommand(INVON);         // Inverse Display on
    
    WriteCommand(MADCTL);        // Memory Access Control
    WriteData(0xC8);

    WriteCommand(COLMOD);        // Set Color Mode
    WriteData(0x03);	         // 12 bit per pixel

    WriteCommand(SETCON);        // Set Contrast
    WriteData(0x30);	

    WriteCommand(NOPP);          // nop
    
    WriteCommand(DISPON);        // Display ON
    
}

void GraphicLCD::Clear(int color)
{
    FillRect(0, 0, 131, 131, color);
}

void GraphicLCD::PutPixel(int x, int y, unsigned int color)
{
    WriteCommand(PASETP);
    WriteData(y);
    WriteData(y);
    
    WriteCommand(CASETP);
    WriteData(x);
    WriteData(x);

    WriteCommand(RAMWRP);
    WriteData((color>>4)&0xFF);    // 0000 BBBB GGGG RRRR >> 4 = 0000 0000 BBBB GGGG
    WriteData(((color&0x0F)<<4));  // 0000 0000 0000 RRRR << 4 = 0000 0000 RRRR 0000
}

void GraphicLCD::FillRect(int x1, int y1, int x2, int y2, int color)
{
    const int max_i = (((x2-x1+1)*(y2-y1+1))/2)+1;
    
    byte byte1 = (color>>4)&0xFF;                         // 0000 BBBB GGGG RRRR => BBBB GGGG
    byte byte2 = ((color&0x0F)<<4) | ((color>>8)&0x0F);   // 0000 BBBB GGGG RRRR => RRRR BBBB
    byte byte3 = color&0xFF;                              // 0000 BBBB GGGG RRRR => GGGG RRRR
    
    WriteCommand(PASETP);
    WriteData(y1);
    WriteData(y2);
    
    WriteCommand(CASETP);
    WriteData(x1);
    WriteData(x2);

    WriteCommand(RAMWRP);

    for(int i=0; i < max_i; i++)
    {
        WriteData(byte1);
        WriteData(byte2);
        WriteData(byte3);
    }
}


// Private Methods //////////////////////////////////////////////////////////////
// Functions available only in this library
void GraphicLCD::Write(byte byte_to_write, byte data_or_command)
{
    // enable chip 
    LCD_CS0;

    // send first bit: (0) for command, (1) for data
    LCD_SET_SDATA(data_or_command);
    LCD_SCLK0;          // pulse clock
    LCD_SCLK1;

    // send the byte, msb first
    LCD_SET_SDATA(byte_to_write>>7);
    LCD_SCLK0;          // pulse clock
    LCD_SCLK1;

    LCD_SET_SDATA(byte_to_write>>6);
    LCD_SCLK0;          // pulse clock
    LCD_SCLK1;

    LCD_SET_SDATA(byte_to_write>>5);
    LCD_SCLK0;          // pulse clock
    LCD_SCLK1;

    LCD_SET_SDATA(byte_to_write>>4);
    LCD_SCLK0;          // pulse clock
    LCD_SCLK1;

    LCD_SET_SDATA(byte_to_write>>3);
    LCD_SCLK0;          // pulse clock
    LCD_SCLK1;

    LCD_SET_SDATA(byte_to_write>>2);
    LCD_SCLK0;          // pulse clock
    LCD_SCLK1;

    LCD_SET_SDATA(byte_to_write>>1);
    LCD_SCLK0;          // pulse clock
    LCD_SCLK1;

    LCD_SET_SDATA(byte_to_write);
    LCD_SCLK0;          // pulse clock
    LCD_SCLK1;

    // disable the chip
    LCD_CS1; 
  
}

GraphicLCD LCD;



